/* eslint-disable @typescript-eslint/restrict-plus-operands */
export interface GridDataInfo {
  data: number[]
  width: number
  east: number
  south: number
  west: number
  north: number
}

const PNGUtil = {
  /**
   *  解析图片成对象
   */
  getGridInfo: function (ctxt: any, img: any, direction: number) {
    const conf = this.getConf(ctxt)
    const hL = conf[0]
    const hLen = conf[1]
    const info = this.getHeader(ctxt, hL, img, hLen)
    info.headerLine = hL
    info.data = this.getGridData(ctxt, hL, img, info, direction)
    return {
      data: info.data,
      width: info.width,
      east: Math.max(info.sLon, info.eLon),
      south: Math.min(info.sLat, info.eLat),
      west: Math.min(info.sLon, info.eLon),
      north: Math.max(info.sLat, info.eLat)
    }
  },
  getConf: function (ctxt: CanvasRenderingContext2D) {
    const pointInfo = ctxt.getImageData(0, 0, 1, 1).data
    return [pointInfo[0], pointInfo[1] + pointInfo[2] * 255]
  },
  getGridData: function (ctxt: CanvasRenderingContext2D, hL: any, img: any, info: any, dirction = -1) {
    // 缩放比
    let scaleFactor = info.scaleFactor
    scaleFactor = scaleFactor || 1
    // 偏移量
    let addOffset = info.addOffset
    addOffset = addOffset || 0
    // 宽度
    const width = img.width
    // 高度
    const height = img.height

    const grids = ctxt.getImageData(0, hL, width, height - hL).data
    const arr: number[] = []
    if (info.sLon > info.eLon) {
      throw new Error('数据异常！格点数据应当从左边开始！')
    }

    if ((info.sLat - info.eLat) * dirction < 0) {
      for (let i = hL, k = 0; i < height; i++) {
        for (let j = 0; j < width; j++, k++) {
          const curIndex = ((i - hL) * width + j) * 4
          arr[k] = (
            grids[curIndex + 3]
              ? (grids[curIndex] +
                grids[curIndex + 1] * 255 +
                grids[curIndex + 2] * 65025) /
              scaleFactor -
              addOffset
              : NaN
          )
        }
      }
    } else {
      for (let i = height - 1, k = 0; i >= hL; i--) {
        for (let j = 0; j < width; j++, k++) {
          const curIndex = ((i - hL) * width + j) * 4
          // arr.push((grids[curIndex]+(grids[curIndex+1]<<8)+(grids[curIndex+2]<<16)) / scaleFactor - addOffset);
          arr[k] = (
            grids[curIndex + 3]
              ? (grids[curIndex] +
                grids[curIndex + 1] * 255 +
                grids[curIndex + 2] * 65025) /
              scaleFactor -
              addOffset
              : NaN
          )
        }
      }
    }

    return arr
  },
  getHeader: function (ctxt: any, hL: any, img: any, hLen: any) {
    const width = img.width
    let headerStr = ''
    const hData = ctxt.getImageData(0, 0, width, hL).data
    const w = Math.floor(hLen / 3) + (hLen % 3 === 0 ? 0 : 1) + 1
    for (let i = 1; i < w; i++) {
      const sub = hLen - 3 * (i - 1)
      if (sub < 3) {
        for (let j = 0; j < sub; j++) {
          headerStr += this.getChar(hData[4 * i + j])
        }
      } else {
        headerStr +=
          this.getChar(hData[4 * i]) +
          this.getChar(hData[4 * i + 1]) +
          this.getChar(hData[4 * i + 2])
      }
    }
    return JSON.parse(decodeURIComponent(atob(headerStr)))
  },
  getChar: function (index: any) {
    if (index === 255) {
      return ''
    }
    return this.charIndex[index]
  },
  charIndex: {
    0: 'A',
    1: 'B',
    2: 'C',
    3: 'D',
    4: 'E',
    5: 'F',
    6: 'G',
    7: 'H',
    8: 'I',
    9: 'J',
    10: 'K',
    11: 'L',
    12: 'M',
    13: 'N',
    14: 'O',
    15: 'P',
    16: 'Q',
    17: 'R',
    18: 'S',
    19: 'T',
    20: 'U',
    21: 'V',
    22: 'W',
    23: 'X',
    24: 'Y',
    25: 'Z',
    26: 'a',
    27: 'b',
    28: 'c',
    29: 'd',
    30: 'e',
    31: 'f',
    32: 'g',
    33: 'h',
    34: 'i',
    35: 'j',
    36: 'k',
    37: 'l',
    38: 'm',
    39: 'n',
    40: 'o',
    41: 'p',
    42: 'q',
    43: 'r',
    44: 's',
    45: 't',
    46: 'u',
    47: 'v',
    48: 'w',
    49: 'x',
    50: 'y',
    51: 'z',
    52: '0',
    53: '1',
    54: '2',
    55: '3',
    56: '4',
    57: '5',
    58: '6',
    59: '7',
    60: '8',
    61: '9',
    62: '+',
    63: '/',
    64: '='
  }
} as any
/**
 * 解析图片数据
 * @param url 图片路径
 * @param isUV 是否是uv风
 * @returns 网格数据
 */

// eslint-disable-next-line @typescript-eslint/promise-function-async
export function readJSONFromImg (url: string, dirction = -1): Promise<GridDataInfo | undefined> {
  return new Promise((resolve) => {
    const img = new Image()
    img.src = url
    img.crossOrigin = 'Anonymous'
    img.onload = () => {
      const canvas = document.createElement('canvas')
      canvas.width = img.width
      canvas.height = img.height
      const ctx = canvas.getContext('2d')
      if (ctx) {
        ctx.drawImage(img, 0, 0)
        const gridDataInfo = PNGUtil.getGridInfo(ctx, img, dirction)
        resolve(gridDataInfo)
      }
    }
    img.onerror = () => {
      resolve(undefined)
    }
  })
}

export function simplifyGrid (grid: GridDataInfo): GridDataInfo {
  const size = [grid.width, grid.data.length / grid.width]
  const { east, south, west, north } = grid
  if (size[0] > 200 || size[1] > 200) {
    const xstep = Math.floor(size[0] / 200)
    const xMore = size[0] % xstep
    const xoffset = xMore === 0 ? 32 : xMore === 1 ? 0 : Math.floor(xMore / 2)
    const xn = (east - west) / (size[0] - 1)
    const ystep = Math.floor(size[1] / 200)
    const yMore = size[0] % ystep
    const yoffset = yMore === 0 ? 32 : yMore === 1 ? 0 : Math.floor(yMore / 2)
    const yn = (north - south) / (size[1] - 1)
    const newSize: [number, number] = [0, 0]
    const newBorder = {
      east: 0,
      south: south + yoffset * yn,
      west: west + xoffset * xn,
      north: 0
    }
    const newdata = []
    for (let j = yoffset; j < size[1]; j += ystep) {
      newBorder.north = south + j * yn
      newSize[1]++
      newSize[0] = 0
      for (let i = xoffset; i < size[0]; i += xstep) {
        newSize[0]++
        newBorder.east = west + i * xn
        newdata.push(grid.data[i + size[0] * j])
      }
    }
    return {
      width: newSize[0],
      ...newBorder,
      data: newdata
    }
  }
  return grid
}
